﻿// ==UserScript==
// @name WME Mass Control
// @description This script selects all of the unknown road type segments.
// @namespace http://www.leafcreations.org
// @grant none
// @version 2.1.0
// @include https://*.waze.com/editor/*
// @include https://*.waze.com/map-editor/*
// @include https://*.waze.com/beta_editor/*
// @include https://editor.waze.com/*
// @include https://editor-beta.waze.com/*
// ==/UserScript==

// How To Use:
// 1) Install this script:
//      A) Compatible with Greasemonkey (Firefox) and Tampermonkey (Chrome)
//      B) Chrome > Tools > Extensions
// 2) Refresh Waze (if open)
// 3) Click MassControl tab and select map service

LCMassControl = {};
LCMassControl.name = "MassControl";
LCMassControl.id = "MassControl";
LCMassControl.version = "2.1.0";

LCMassControl.controls = {};
LCMassControl.controls.roads = {};
LCMassControl.controls.roads.name = LCMassControl.name + '_roads';
LCMassControl.controls.roads.id = LCMassControl.name + '_roads';

LCMassControl.controls.cameras = {};
LCMassControl.controls.cameras.name = LCMassControl.name + '_cameras';
LCMassControl.controls.cameras.id = LCMassControl.name + '_cameras';

LCMassControl.controls.options = {};
LCMassControl.controls.options.name = LCMassControl.name + '_options';
LCMassControl.controls.options.id = LCMassControl.name + '_options';

LCMassControl.controls.nodes = {};
LCMassControl.controls.nodes.name = LCMassControl.name + '_nodes';
LCMassControl.controls.nodes.id = LCMassControl.name + '_nodes';

LCMassControl.controls.mapproblems = {};
LCMassControl.controls.mapproblems.name = LCMassControl.name + '_mapproblems';
LCMassControl.controls.mapproblems.id = LCMassControl.name + '_mapproblems';

LCMassControl.user = '';
LCMassControl.userRank = 0;

LCMassControl.enums = {};
LCMassControl.enums.roadDirections = {
    Unknown: 0,
    OneWayAB: 1,
    OneWayBA: 2,
    Twoway: 3,
    UnnamedSegment: 4
}

LCMassControl.enums.userRanks = {
    Level1: 0,
    Level2: 1,
    Level3: 2,
    Level4: 3,
    Level5: 4,
    Level6: 5
}
LCMassControl.enums.roadTypes = {
    Street: 1,
    PrimaryStreet: 2,
    Freeway: 3,
    Ramp: 4,
    MajorHighway: 6,
    MinorHighway: 7,
    DirtRoad: 8,
    PrivateRoad: 17,
    Railroad: 18,
    ParkingLotRoad: 20,
    ServiceRoad: 21
}

// ******************************************************************************
// INITIATES THE USER SCRIPT - CALLED AT LIST LINE OF SCRIPT
// ******************************************************************************
LCMassControl.bootstrap = function () {
    var bGreasemonkeyServiceDefined = false;

    try {
        bGreasemonkeyServiceDefined = (typeof Components.interfaces.gmIGreasemonkeyService === "object");
    }
    catch (err) { /* Ignore */ }

    if (typeof unsafeWindow === "undefined" || !bGreasemonkeyServiceDefined) {
        unsafeWindow = (function () {
            var dummyElem = document.createElement('p');
            dummyElem.setAttribute('onclick', 'return window;');
            return dummyElem.onclick();
        })();
    }

    /* begin running the code! */
    setTimeout(LCMassControl.initialize, 500);
}

// ******************************************************************************
// HELPER FUNCTIONS
// ******************************************************************************
LCMassControl.helper = {};
LCMassControl.helper.getElementsByClassName = function (classname, node) {
    if (!node) node = document.getElementsByTagName("body")[0];
    var a = [];
    var re = new RegExp('\\b' + classname + '\\b');
    var els = node.getElementsByTagName("*");
    for (var i = 0, j = els.length; i < j; i++)
        if (re.test(els[i].className)) a.push(els[i]);
    return a;
}
LCMassControl.helper.getId = function (node) {
    return document.getElementById(node);
}
LCMassControl.helper.getQueryString = function (link, name) {
    var pos = link.indexOf(name + '=') + name.length + 1;
    var len = link.substr(pos).indexOf('&');
    return link.substr(pos, len);
}

// ******************************************************************************
// HTML HELPER FUNCTIONS
// ******************************************************************************
LCMassControl.html = {};
LCMassControl.html.createSection = function (name) {
    var section = document.createElement('p');
    section.name = name;
    section.style.fontSize = '10px';

    return section
}
LCMassControl.html.createButton = function (name) {
    var item = document.createElement('button');
    item.innerHTML = name;
    item.style.width = '150px';

    return item
}
LCMassControl.html.createSelector = function (rType, rId, rName, rValue, rText, isChecked) {
    var _isChecked = ''

    if (isChecked == true) {
        _isChecked = 'checked';
    }

    return '<input type="' + rType + '" id="' + rId + '" name="' + rName + '" value="' + rValue + '"' + _isChecked + ' /> ' + rText + '&nbsp;'

}
LCMassControl.html.createRadioDOM = function (rID, rValue, rName, rText, isChecked) {

    var radio = document.createElement('input');
    radio.type = 'radio';
    radio.id = rID;
    radio.value = rValue;
    radio.name = rName;

    if (isChecked) { radio.checked = true; }

    radio.addEventListener('click', function () {
        LCMassControl.events.selectControl(radio.id)
    });
    var objTextNode = document.createTextNode(' ' + rText);
    var objLabel = document.createElement("label");
    objLabel.htmlFor = radio.id;
    objLabel.appendChild(radio);
    objLabel.appendChild(objTextNode);

    return objLabel

}
LCMassControl.html.createCheckBoxDOM = function (rID, rValue, rName, rText, isChecked) {

    var checkbox = document.createElement('input');
    checkbox.type = 'checkbox';
    checkbox.id = rID;
    checkbox.value = rValue;
    checkbox.name = rName;

    if (isChecked) { checkbox.checked = true; }

    checkbox.addEventListener('click', function () {
        LCMassControl.events.hideName(checkbox.id)
    });
    var objTextNode = document.createTextNode(' ' + rText);
    var objLabel = document.createElement("label");
    objLabel.htmlFor = checkbox.id;
    objLabel.appendChild(checkbox);
    objLabel.appendChild(objTextNode);

    return objLabel

}
// ******************************************************************************

LCMassControl.objects = {};
LCMassControl.objects.roads = function () {

    var s1 = LCMassControl.helper.getId('rType');
    var s2 = LCMassControl.helper.getId('rDirection');
    var s3 = LCMassControl.helper.getId('sLimit');
    var s4 = LCMassControl.helper.getId('rLockLevel');

    var rType = s1.options[s1.selectedIndex].value;
    var rDirection = s2.options[s2.selectedIndex].value;
    var sLimit = s3.options[s3.selectedIndex].value;
    var rLockLevel = s4.options[s4.selectedIndex].value;

    this.roadType = parseInt(rType);
    this.roadDirection = parseInt(rDirection);
    this.selectionLimit = parseInt(sLimit);
    this.roadLockLevel = parseInt(rLockLevel);

}
LCMassControl.objects.options = function () {
    var c1 = LCMassControl.helper.getId('c1_islocked');
    var c2 = LCMassControl.helper.getId('c1_disableAlert');

    this.observeLockProperty = c1.checked;
    this.disableAlert = c2.checked;
}
LCMassControl.objects.cameras = function () {
    var c1 = LCMassControl.helper.getId('cType');
    var c2 = LCMassControl.helper.getId('cDays');

    var cType = c1.options[c1.selectedIndex].value;
    var cDays = c2.options[c2.selectedIndex].value;

    this.cameryType = cType;
    this.selectionDays = cDays;

}
LCMassControl.objects.nodes = function () {
    var s1 = LCMassControl.helper.getId('nFixCount');
    var r1 = LCMassControl.helper.getId('r1_node_fix');
    var r2 = LCMassControl.helper.getId('r2_node_fix');


    var nodeSelection = s1.options[s1.selectedIndex].value;
    var nodeFixSoft = r1.checked;
    var nodeFixDisabled = r2.checked;


    this.nodeSelectionCount = nodeSelection;
    this.fixSoftTurns = nodeFixSoft;
    this.fixDisabled = nodeFixDisabled;
}
// ******************************************************************************
// EVENTS HELPER FUNCTIONS
// ******************************************************************************
LCMassControl.events = {};
LCMassControl.events.validateSegment = function (seg) {

    // Must be <= to user's rank
    if (seg.getLockRank() > LCMassControl.userRank) { return false; }

    // Must be on screen
    if (!seg.onScreen()) { return false; }

    // Properties must be editable
    if (!seg.arePropertiesEditable()) { return false; }

    // Must not be deleted
    if (seg.isDeleted()) { return false; }

    return true;
}

LCMassControl.events.validateCamera = function (cam) {
    // Must be on screen
    if (!cam.onScreen()) { return false; }

    // Must not be validated
    if (cam.attributes.validated) { return false; }

    // Must not be deleted
    if (cam.isDeleted()) { return false; }

    if (!cam.arePropertiesEditable()) { return false; }

    return true;

}

LCMassControl.events.massSelect = function () {

    var obj = wazeModel.segments.objects
    var foundSegs = new Array();        

    var roadInfo = new LCMassControl.objects.roads();
    var options = new LCMassControl.objects.options();

    var iCount = 0;

    for (var key in obj) {
        var o = obj[key];

        if (LCMassControl.events.validateSegment(o)) {

            if (!LCMassControl.events.observeLock(options.observeLockProperty, o.attributes.locked)) {

                if (parseInt(o.attributes.roadType) == roadInfo.roadType) {

                    if (parseInt(o.attributes.lockRank) <= roadInfo.roadLockLevel) {

                        if (parseInt(o.getDirection()) == parseInt(roadInfo.roadDirection)) {

                            var streets = new Array();
                            streets = o.getAddress();

                            if (streets.street.name != null) {
                                foundSegs.push(wazeModel.segments.objects[o.fid]);
                                iCount++;
                            }
                        }
                        if (parseInt(roadInfo.roadDirection) == LCMassControl.enums.roadDirections.UnnamedSegment) {
                            if (o.attributes.primaryStreetID == null) {
                                foundSegs.push(wazeModel.segments.objects[o.fid]);
                                iCount++;
                            }
                        }
                    }
                }
            }
        }
        if (iCount == roadInfo.selectionLimit) {
            break;
        }        
    }

    if (foundSegs.length > 0) {
        if (!options.disableAlert) { alert('There are ' + foundSegs.length + ' segments that have been selected.'); }
        selectionManager.selectControl.selectMultiple(foundSegs);
    }
}

LCMassControl.events.forNodes = {};
LCMassControl.events.forNodes.fixNodes = function () {

    
    var nodes = wazeModel.nodes.objects;    
        
    var nCount = 0;

    var has_soft = false;
    var has_revcon = false;
    var has_selfcon = false;

    var nodeInfo = new LCMassControl.objects.nodes();

    for (var obj in nodes) {
        var node = nodes[obj];        

        nCount++;

        has_soft = false;
        has_revcon = false;
        has_selfcon = false;        

        if (node.onScreen()) {
            
            if (node.attributes.segIDs.length > 0) {
                
                for (var i = 0; i < node.attributes.segIDs.length; i++) {

                    var seg = wazeModel.segments.get(node.attributes.segIDs[i]);

                    if (seg.getDirection() != LCMassControl.enums.roadDirections.Unknown) {

                        if (nodeInfo.fixSoftTurns) {

                            if (!has_soft && ((seg.attributes.toNodeID == node.fid && !seg.attributes.fwdTurnsLocked) ||
                                                (seg.attributes.fromNodeID == node.fid && !seg.attributes.revTurnsLocked))) {
                                has_soft = true;

                            }

                            if (has_soft) {
                                wazeModel.actionManager.add(new Waze.Action.ModifyAllConnections(node, false));
                                wazeModel.actionManager.add(new Waze.Action.ModifyAllConnections(node, true));
                            }

                        }

                        if (nodeInfo.fixDisabled) {
                            if (!node.areAllConnectionsEnabled()) {                                
                                wazeModel.actionManager.add(new Waze.Action.ModifyAllConnections(node, true));
                            }
                        }
                    }
                }
            }
        }
        if (nCount == nodeInfo.nodeSelectionCount) { break; }
    }
}

LCMassControl.events.forNodes.deleteNodes = function () {
    var nodes = wazeModel.nodes.objects;
    var foundNodes = new Array();

    var options = new LCMassControl.objects.options()

    for (var obj in nodes) {
        var node = nodes[obj];

        if (node.onScreen()) {           
            foundNodes.push(wazeModel.nodes.objects[node.fid]);
        }
    }
    if (foundNodes.length > 0) {
        if (!options.disableAlert) { alert('There were ' + foundNodes.length + ' nodes scanned.'); }
        wazeModel.deleteNodes(foundNodes);
    }
}


LCMassControl.events.selectUnknown = function () {
    var obj = wazeModel.segments.objects
    var foundSegs = new Array();

    var roadInfo = new LCMassControl.objects.roads();
    var options = new LCMassControl.objects.options();

    var iCount = 0    

    for (var key in obj) {
        var o = obj[key];        

        if (LCMassControl.events.validateSegment(o)) {

            if (!LCMassControl.events.observeLock(options.observeLockProperty, o.attributes.locked)) {

                if (!LCMassControl.events.IsPartialNode(o.attributes.fromNodeID) && !LCMassControl.events.IsPartialNode(o.attributes.toNodeID)) {

                    if (parseInt(o.getDirection()) == roadInfo.roadDirection) {

                        if (o.attributes.roadType == roadInfo.roadType) {

                            if (roadInfo.roadType != LCMassControl.enums.roadTypes.Railroad) {
                                var streets = new Array();
                                streets = o.getAddress();

                                if (streets.street.name === null) {
                                    foundSegs.push(wazeModel.segments.objects[o.fid]);
                                    iCount++;
                                }
                            }
                            else {
                                foundSegs.push(wazeModel.segments.objects[o.fid]);
                                iCount++;
                            }
                        }
                    }
                    if (parseInt(rDirection) == LCMassControl.enums.roadDirections.UnnamedSegment) {
                        if (o.attributes.primaryStreetID == null) {
                            foundSegs.push(wazeModel.segments.objects[o.fid]);
                            iCount++;
                        }
                    }
                }
            }
        }
        if (iCount == roadInfo.selectionLimit) {
            break;
        }

    }

    if (foundSegs.length > 0) {
        if (!options.disableAlert) { alert('There are ' + foundSegs.length + ' segments that have been selected for deletion.'); }
        wazeModel.deleteSegments(foundSegs);
    }
}

LCMassControl.events.IsPartialNode = function (nodeID) {

    if (nodeID == null) { return false; }

    var node = wazeModel.nodes.get(nodeID);

    for (var key in node.data) {
        if (key === 'partial') return true;
    }
}

LCMassControl.events.observeLock = function (isChecked, isLocked) {

    if (!isChecked) { return false };

    if (isLocked) { return true };

    return false;
}

LCMassControl.events.selectCameras = function () {

    var cameras = new LCMassControl.objects.cameras();
    var options = new LCMassControl.objects.options();    

    var obj = wazeModel.cameras.objects
    var foundSegs = new Array();

    var iCount = 0

    var today = new Date()

    for (var key in obj) {
        var o = obj[key];

        if (LCMassControl.events.validateCamera(o)) {
            if (o.attributes.type = cameras.cameryType) {

                var date = new Date(o.attributes.createdOn)

                var tDay = today.getDate();
                var cDay = date.getDate();

                if (Math.abs(tDay - cDay) >= cameras.selectionDays
                    ) {
                    foundSegs.push(wazeModel.cameras.objects[o.fid]);
                }
            }
        }        
        if (iCount == sLimit) {
            break;
        }

    }

    if (foundSegs.length > 0) {
        if (!options.disableAlert) { alert('There are ' + foundSegs.length + ' segments that have been selected for deletion.'); }
        wazeModel.deleteObjects(foundSegs);
    }
}

LCMassControl.events.selectControl = function (controlid) {

    if (controlid == null) { return };

    var ctl1 = LCMassControl.helper.getId(LCMassControl.controls.roads.id);
    var ctl2 = LCMassControl.helper.getId(LCMassControl.controls.nodes.id);
    var ctl3 = LCMassControl.helper.getId(LCMassControl.controls.cameras.id);    
    var ctl4 = LCMassControl.helper.getId(LCMassControl.controls.options.id);

    switch (controlid) {
        case 'r1_control':
            ctl1.style.display = 'block';
            ctl2.style.display = 'none';
            ctl3.style.display = 'none';
            ctl4.style.display = 'none';
            //ctl5.style.display = 'none';
            break;
        case 'r2_control':
            ctl1.style.display = 'none';
            ctl2.style.display = 'block';
            ctl3.style.display = 'none';
            ctl4.style.display = 'none';
            //ctl5.style.display = 'none';
            break;
        case 'r3_control':
            ctl1.style.display = 'none';
            ctl2.style.display = 'none';
            ctl3.style.display = 'block';
            ctl4.style.display = 'none';
            //ctl5.style.display = 'none';
            break;
        case 'r4_control':
            ctl1.style.display = 'none';
            ctl2.style.display = 'none';
            ctl3.style.display = 'none';
            ctl4.style.display = 'block';
            //ctl5.style.display = 'none';
            break;
        case 'r5_control':
            ctl1.style.display = 'none';
            ctl2.style.display = 'none';
            ctl3.style.display = 'none';
            ctl4.style.display = 'none';
            //ctl5.style.display = 'block';
            break;
    }        
}

LCMassControl.events.hideName = function (checkboxid) {    

    var ctl = LCMassControl.helper.getId(checkboxid);
    var hdr = LCMassControl.helper.getId('user-greeting');

    if (ctl.checked) {
        hdr.style.display = 'none';
    }
    else {
        hdr.style.display = 'block';
    }


};


// ******************************************************************************
// BUILDS THE TAB AND ITS CONTENT
// ******************************************************************************
LCMassControl.initialize = function () {

    // access the bits of WME we need
    Waze = unsafeWindow.Waze;
    wazeMap = unsafeWindow.wazeMap;
    wazeModel = unsafeWindow.wazeModel;
    loginManager = unsafeWindow.loginManager;
    selectionManager = unsafeWindow.selectionManager;

    LCMassControl.user = loginManager.user.userName;
    LCMassControl.userRank = loginManager.user.rank;

    // Top Header includes:
    // 1. Link
    // 2. Control Options
    var addon = document.createElement('div');
    addon.id = LCMassControl.id;
    addon.innerHTML = '<a href="http://userscripts.org/scripts/show/165345" target="_blank">MassControl</a> v' + LCMassControl.version;

    // Table that stores the available controls
    var table = document.createElement('table');
    table.style.width = '100%';
    table.style.borderBottom = '1px solid #D8D8D8';
    table.style.marginBottom = '5px';

    var tr = document.createElement('tr');

    var td1 = document.createElement('td');
    td1.vAlign = 'top';
    td1.style.width = '40%';
    var td2 = document.createElement('td');
    td2.vAlign = 'top';
    td1.style.width = '60%';

    // First Control
    var rButton = LCMassControl.html.createRadioDOM('r1_control', 'r', 'control_type', 'Roads',true);    
    td1.appendChild(rButton);    

    // Second Control
    var rButton = LCMassControl.html.createRadioDOM('r2_control', 'n', 'control_type', 'Nodes',false);
    td1.appendChild(rButton);

    // Third Control
    var rButton = LCMassControl.html.createRadioDOM('r3_control', 'c', 'control_type', 'Cameras', false);
    td1.appendChild(rButton);

    // Third Control
    var rButton = LCMassControl.html.createRadioDOM('r4_control', 'o', 'control_type', 'Options', false);
    td2.appendChild(rButton);    

    tr.appendChild(td1);
    tr.appendChild(td2);

    table.appendChild(tr);

    addon.appendChild(table);    

    
    // DIVS for each control type
    var addonRoad = document.createElement('div');
    addonRoad.id = LCMassControl.controls.roads.id;
    addonRoad.style.display = 'display';
    
    addon.appendChild(addonRoad);

    var addonCamera = document.createElement('div');
    addonCamera.id = LCMassControl.controls.cameras.id;
    addonCamera.style.display = 'none';

    addon.appendChild(addonCamera);

    var addonNodes = document.createElement('div');
    addonNodes.id = LCMassControl.controls.nodes.id;
    addonNodes.style.display = 'none';

    addon.appendChild(addonNodes);

    var addonOptions = document.createElement('div');
    addonOptions.id = LCMassControl.controls.options.id;
    addonOptions.style.display = 'none';

    addon.appendChild(addonOptions);

    //
    // -- START ADD OF SERVICES
    //    
    
    var section = document.createElement('p');
    section.style.marginBottom = '0px';    

    section.innerHTML = 'Select the Road Type: <br>' +
                        '<select name="rType" id="rType">' +
                        '<optgroup label="Highways">' +
                        '<option value="3">Freeway</option>' +
                        '<option value="7">Minor Highway</option>' +
                        '<option value="6">Major Highway</option>' +
                        '<option value="4">Ramp</option>' +
                        '</optgroup>' +
                        '<optgroup label="Streets">' +
                        '<option value="2">Primary Street</option>' +
                        '<option value="1" selected="selected">Street</option>' +
                        '<option value="21">Service Road</option>' +
                        '</optgroup>' +
                        '<optgroup label="Other - drivable">' +
                        '<option value="8">Dirt road / 4x4 Trail</option>' +                        
                        '<option value="20">Parking Lot Road</option>' +
                        '<option value="17">Private Road</option>' +
                        '</optgroup>' +
                        '<optgroup label="Non-drivable">' +
                        '<option value="18">Railroad</option>' +
                        '</optgroup>' +
                        '</select>'
    addonRoad.appendChild(section);

    var section = document.createElement('p');
    section.style.marginBottom = '0px';

    section.innerHTML = 'Select the Direction: <br>' +
                        '<select name="rDirection" id="rDirection">' +
                        '<option value="0">Unknown</option>' +
                        '<option value="1">One Way (A - B)</option>' +
                        '<option value="2">One Way (B - A)</option>' +
                        '<option value="3">Two-way</option>' +
                        '<option value="4">Unnamed segment</option>' +
                        '</select>'
    addonRoad.appendChild(section);

    var section = document.createElement('p');
    section.style.marginBottom = '0px';

    var optString    

    for (var i = 0; i <= LCMassControl.userRank; i++) {
        var opt

        if (i == LCMassControl.userRank) {
            opt = '<option value="' + i + '" selected="selected">Level ' + (i + 1) + '</option>'
        }
        else {
            opt = '<option value="' + i + '">Level ' + (i + 1) + '</option>'
        }

        optString = optString + opt
    }

    section.innerHTML = 'Lock Level (<=): <br>' +
                        '<select name="rLockLevel" id="rLockLevel">' + optString +
                        '</select>'
    addonRoad.appendChild(section);

    var section = document.createElement('p');
    section.style.marginBottom = '0px';

    section.innerHTML = 'Selection Limit: <br>' +
                        '<select name="sLimit" id="sLimit">' +
                        '<option value="5">5</option>' +
                        '<option value="9" selected="selected">9</option>' +
                        '<option value="15">15</option>' +
                        '<option value="20">20</option>' +
                        '<option value="50">50</option>' +
                        '<option value="100">100</option>' +
                        '</select>'
    addonRoad.appendChild(section);

    var btn = LCMassControl.html.createButton('Delete Roads');
    btn.onclick = function () { LCMassControl.events.selectUnknown() };    
    addonRoad.appendChild(btn);

    var btn1 = LCMassControl.html.createButton('Select Roads');
    btn1.onclick = function () { LCMassControl.events.massSelect() };
    addonRoad.appendChild(btn1);

    var section = document.createElement('p');
    section.style.marginBottom = '0px';

    section.innerHTML = 'Camera Type: <br>' +
                        '<select name="cType" id="cType">' +
                        '<option value="2">Speed Camera</option>' +
                        '<option value="3" selected="selected">Dummy</option>' +
                        '<option value="4">Red light Camera</option>' +
                        '</select>'
    addonCamera.appendChild(section);

    var section = document.createElement('p');
    section.style.marginBottom = '0px';

    section.innerHTML = 'Days Old: <br>' +
                        '<select name="cDays" id="cDays">' +
                        '<option value="5">5</option>' +
                        '<option value="9" selected="selected">9</option>' +
                        '<option value="14">14</option>' +
                        '</select>'
    addonCamera.appendChild(section);

    var btn = LCMassControl.html.createButton('Delete Cameras');
    btn.onclick = function () { LCMassControl.events.selectCameras() };
    addonCamera.appendChild(btn);

    var section = document.createElement('p');
    section.style.paddingTop = '15px';
    section.innerHTML = 'Fix: <br>' +
                        LCMassControl.html.createSelector('radio', 'r1_node_fix', 'node_fix', 's', 'Soft Turns', true) + '<br>' +
                        LCMassControl.html.createSelector('radio', 'r2_node_fix', 'node_fix', 'd', 'Disabled Turns', false)
    addonNodes.appendChild(section);

    var section = document.createElement('p');
    section.innerHTML = 'Number of Fixes: <br>' +
                    '<select name="nFixCount" id="nFixCount">' +
                    '<option value="100" selected="selected">100</option>' +
                    '<option value="200">200</option>' +
                    '<option value="300">300</option>' +
                    '<option value="400">400</option>' +
                    '</select>'

    var btn2 = LCMassControl.html.createButton('Fix Nodes');
    btn2.onclick = function () { LCMassControl.events.forNodes.fixNodes() };
    section.appendChild(btn2);

    addonNodes.appendChild(section);

    var section = document.createElement('p');
    section.innerHTML = 'Other: <br>';

    var btn2 = LCMassControl.html.createButton('Delete Nodes');
    btn2.onclick = function () { LCMassControl.events.forNodes.deleteNodes() };
    section.appendChild(btn2);
        
    addonNodes.appendChild(section);
    

    var section = document.createElement('p');
    section.innerHTML = 'Options: <br>' +
                        LCMassControl.html.createSelector('checkbox', 'c1_islocked', 'isLocked', 'n', 'Observe "locked" flag', false) + '<br>' +                        
                        LCMassControl.html.createSelector('checkbox', 'c1_disableAlert', 'disableAlert', 'n', 'Disable message box', true);

    var cBox = LCMassControl.html.createCheckBoxDOM('c1_hideName', 'hideName', 'hn', 'Hide Name', false);
    section.appendChild(cBox);

    addonOptions.appendChild(section);

    //
    // -- END ADD OF SERVICES
    //

    //
    // -- START ADD USER TAB
    //

    var userTabs = LCMassControl.helper.getId('user-tabs');
    var navTabs = LCMassControl.helper.getElementsByClassName('nav-tabs', userTabs)[0];
    var tabContent = LCMassControl.helper.getElementsByClassName('tab-content', userTabs)[0];

    newtab = document.createElement('li');
    newtab.innerHTML = '<a href="#sidepanel-' + LCMassControl.id + '" data-toggle="tab">' + LCMassControl.name + '</a>';
    navTabs.appendChild(newtab);

    addon.id = 'sidepanel-' + LCMassControl.id;
    addon.className = "tab-pane";
    tabContent.appendChild(addon);

    //
    // -- END ADD USER TAB
    //        

}
    // ******************************************************************************

    // ******************************************************************************
    // MassControl IS A GO!
    // ******************************************************************************
    LCMassControl.bootstrap();
    // ******************************************************************************